// 路径: com.reliable.service.service.impl.ChunkServiceImpl
package com.reliable.service.serviceimpl;

import com.reliable.service.oss.service.OssService;
import com.reliable.service.domain.ReliabUploadRecord;
import com.reliable.service.service.ChatMessageService;
import com.reliable.service.service.ChunkService;
import com.reliable.service.service.IReliabUploadRecordService;
import com.reliable.service.utils.IdEncryptUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class ChunkServiceImpl implements ChunkService {

    @Value("${upload.temp-dir:/tmp/upload-chunks}")
    private String tempDir;

    @Autowired
    private ChatMessageService chatMessageService;

    @Autowired
    private OssService ossService;

    @Autowired
    private IReliabUploadRecordService uploadRecordService;

    @Override
    public List<Integer> getUploadedChunks(String fileHash) {
        Path dir = Paths.get(tempDir, fileHash);
        if (!Files.exists(dir)) return java.util.Collections.emptyList();
        try (Stream<Path> stream = Files.list(dir)) {
            return stream
                .filter(p -> !".meta".equals(p.getFileName().toString()))
                .map(this::tryParseInt)
                .filter(java.util.Objects::nonNull)
                .sorted()
                .collect(Collectors.toList());
        } catch (IOException e) {
            return java.util.Collections.emptyList();
        }
    }

    private Integer tryParseInt(Path p) {
        try {
            return Integer.valueOf(p.getFileName().toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    @Override
    public void saveChunk(MultipartFile chunk, String fileHash, int chunkIndex, String originalFilename) throws IOException {
        // ✅ 清洗 fileHash：去除首尾空格、非法字符（如逗号）
        if (fileHash == null || fileHash.trim().isEmpty()) {
            throw new IllegalArgumentException("fileHash 不能为空");
        }
        // 只保留字母、数字、下划线、短横线，替换其他字符为下划线
        String cleanHash = fileHash.trim()
                .replaceAll("[^a-zA-Z0-9_-]", "_")   // 先替换非法字符
                .replaceAll("_+", "_")               // 多个下划线合并为一个
                .replaceAll("_$", "");               // 移除末尾下划线

        Path dir = Paths.get(tempDir, cleanHash); // ← 使用清洗后的 cleanHash！
        Files.createDirectories(dir);

        Path chunkFile = dir.resolve(String.valueOf(chunkIndex));
        chunk.transferTo(chunkFile.toFile());

        // 保存元数据（文件名）
        Files.write(dir.resolve(".meta"), (originalFilename + "\n" + System.currentTimeMillis()).getBytes());
        log.info("保存分片元数据: {}", chunkFile);
    }

    @Override
    public void mergeAndImportExcel(String fileHash, String originalFilename, String taskId) throws Exception {
        Path dir = Paths.get(tempDir, cleanFileHash(fileHash)); // 先清洗
        if (!Files.exists(dir)) {
            throw new FileNotFoundException("分片目录不存在: " + dir);
        }

        File mergedFile = null;
        try {
            // 1. 合并分片
            mergedFile = mergeChunks(dir, originalFilename);

            // 2. 上传 OSS
            String ossUrl = ossService.uploadFile(mergedFile);

            // 3. 导入数据库
            Long decryptTaskId = IdEncryptUtils.decrypt(taskId);
            chatMessageService.importExcelFromFile(mergedFile, originalFilename, decryptTaskId);

            // 4. 更新 OSS URL
            Long uploadId = uploadRecordService.getUploadIdByTaskId(decryptTaskId);
            if (uploadId != null) {
                uploadRecordService.updateOssUrl(uploadId, ossUrl);
            }

        } finally {
            // ✅ 5. 【关键】自动销毁临时目录（无论成功/失败）
            if (mergedFile != null) {
                mergedFile.delete(); // 删除合并后的临时文件
            }
            deleteChunkDir(dir); // 删除分片目录
        }
    }

    // 安全删除分片目录（递归）
    private void deleteChunkDir(Path dir) {
        if (Files.exists(dir)) {
            try (Stream<Path> stream = Files.walk(dir)) {
                stream.sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
                        .forEach(file -> {
                            if (!file.delete()) {
                                log.warn("无法删除临时文件: {}", file.getAbsolutePath());
                            }
                        });
            } catch (Exception e) {
                log.error("清理分片目录失败: {}", dir, e);
            }
        }
    }

    // 清洗 fileHash（防止路径注入）
    private String cleanFileHash(String fileHash) {
        return fileHash.replaceAll("[^a-zA-Z0-9_-]", "_");
    }

    private File mergeChunks(Path chunkDir, String filename) throws IOException {
        List<Path> chunks = Files.list(chunkDir)
            .filter(p -> !".meta".equals(p.getFileName().toString()))
            .sorted((a, b) -> Integer.compare(tryParseInt(a), tryParseInt(b)))
            .collect(Collectors.toList());

        File merged = File.createTempFile("merged_", "_" + filename);
        try (FileChannel out = FileChannel.open(merged.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
            for (Path chunk : chunks) {
                try (FileChannel in = FileChannel.open(chunk, StandardOpenOption.READ)) {
                    in.transferTo(0, in.size(), out);
                }
            }
        }
        return merged;
    }

}